package name.cyrax.red.jpv.impl.funcs.core;

import name.cyrax.red.jpv.api.adapters.DoubleAdapter;
import name.cyrax.red.jpv.api.adapters.IntegerAdapter;
import name.cyrax.red.jpv.api.adapters.LongAdapter;
import name.cyrax.red.jpv.api.adapters.NumericAdapter;
import name.cyrax.red.jpv.api.funcs.BoundUnaryFunctor;
import name.cyrax.red.jpv.api.funcs.FunctorInstance;
import name.cyrax.red.jpv.api.funcs.Invocable;
import name.cyrax.red.jpv.api.funcs.info.FunctorMethod;
import name.cyrax.red.jpv.api.funcs.info.ValueType;
import name.cyrax.red.jpv.impl.adapters.LongImpl;
import name.cyrax.red.jpv.impl.vectors.VectorFactories;

public abstract class FunctorUnaryLongImpl
	extends FunctorAbstractUnaryImpl<LongAdapter> implements BoundUnaryFunctor<Long>
{
	private static final String OP_METHOD_NAME = "opLong"; 
	private static final ValueType OP_RESULT_TYPE = ValueType.LONG; 
	private static final Class<?> OP_METHOD_CLASS = FunctorUnaryLongImpl.class; 
	
	private final FunctorInstance funcInstance = getFunctorInstance(
		FunctorMethod.newMethod(OP_METHOD_CLASS,
			OP_METHOD_NAME, OP_RESULT_TYPE, ValueType.UNKNOWN));
	
	@Override public LongAdapter newAdapter(final IntegerAdapter p0) {
		return newAdapter(funcInstance, p0);
	}
	@Override public LongAdapter newAdapter(final LongAdapter p0) {
		return newAdapter(funcInstance, p0);
	}
	@Override public LongAdapter newAdapter(final DoubleAdapter p0) {
		return newAdapter(funcInstance, p0);
	}
	
	public abstract long opLong(int v0);
	public abstract long opLong(long v0);
	public abstract long opLong(double v0);
	
	private abstract class UnaryLongImpl<N extends NumericAdapter> extends LongImpl {
		private final FunctorInstance fi;
		private final N p0;		
	
		public UnaryLongImpl(FunctorInstance fi, N p0)
		{
			this.fi = fi;
			this.p0 = p0;
		}			
		@Override public FunctorInstance getFunctorInstance() {
			return fi;
		}
		@Override public NumericAdapter getParam(int index) {
			return switchOf(index, p0);
		}
		@Override public int size() { return p0.size(); }
	}; 
	
	
	final LongAdapter newAdapter(FunctorInstance fi, final IntegerAdapter p0) {
		return checkAdapterType(new UnaryLongImpl<IntegerAdapter>(fi, p0) {
			@Override public long getLong(int index) {
				return opLong(p0.getInteger(index));
			}
		});
	}
	final LongAdapter newAdapter(FunctorInstance fi, final LongAdapter p0) {
		return checkAdapterType(new UnaryLongImpl<LongAdapter>(fi, p0) {
			@Override public long getLong(int index) {
				return opLong(p0.getLong(index));
			}
		});
	}
	final LongAdapter newAdapter(FunctorInstance fi, final DoubleAdapter p0) {
		return checkAdapterType(new UnaryLongImpl<DoubleAdapter>(fi, p0) {
			@Override public long getLong(int index) {
				return opLong(p0.getDouble(index));
			}
		});
	}		
	
	protected final Invocable<Long> newInvocable0(Invocable<?> v0)
	{
		return new UnaryInvocableImpl<>(VectorFactories.getLong(), v0);
	}
	
	@Override public Invocable<Long> newInstance(Invocable<?> v0)
	{
		return newInvocable0(v0);
	}
}
